/*******************************************************************/
/* @ All Rights Reserved Copyright (C) 2014 broada,Co.,Ltd.        */
/*                                                                 */
/*  NAME      = ldap_parse.c                                       */
/*  NOTE      =                                                    */
/*  DATE      = 2015/07/27 by geyh                                 */
/*******************************************************************/
#include<stdio.h>
#include<stdlib.h>

#include"frcomm.h"
#include"frbyte_buffer.h"
#include"frlist.h"
#include "frct_comm.h"

#include "ldap_base_data.h"
#include "ldap_comm.h"
#include "ldap_parse.h"

int ldap_protocol_parse_req(Frbyte_Packet *p_packet, Frreport_body_data *p_st_body_data, unsigned int ui_tmp, L7session_ldap_private *p_st_private)
{
    int i_ret = 0;

    if(p_packet == NULL || p_st_body_data == NULL)
        return FR_FAIL;

    switch (ui_tmp)
    {
        case BIND_REQ:
            i_ret = ldap_bind_request(p_packet, p_st_body_data, p_st_private);
            p_st_private->i_flag_data_type = FRLOGIN_START;
            p_st_private->i_flag_report = 0;
            break;

        case UNBIND_REQ:
            i_ret = FR_SUCC;
            p_st_private->i_flag_data_type = FRLOGOUT_END;
            p_st_private->i_flag_report = 0;
            break;

        case SEARCH_REQ:
            i_ret = ldap_search_request(p_packet, p_st_body_data, p_st_private);
            p_st_private->i_flag_report = 1;
            break;

        case MOD_DN_REQ:
            i_ret = ldap_modDN_request(p_packet, p_st_body_data, p_st_private);
            p_st_private->i_flag_report = 1;
            break;

        case ADD_REQ:
            i_ret = ldap_add_request(p_packet, p_st_body_data, p_st_private);
            p_st_private->i_flag_report = 1;
            break;

        case DEL_REQ:
            i_ret = ldap_del_request(p_packet, p_st_body_data, p_st_private);
            p_st_private->i_flag_report = 1;
            break;

        case ABAND_REQ:
            i_ret = ldap_abandon_request(p_packet, p_st_body_data, p_st_private);
            p_st_private->i_flag_report = 1;
            break;

        case MOD_REQ:
            i_ret = ldap_modify_request(p_packet, p_st_body_data, p_st_private);
            p_st_private->i_flag_report = 1;
            break;

        default:
            return APM_L7_ANALYZE_FAIL;
    }

//    if(i_ret == FR_FAIL)
//        printf("ui_tmp = %x\n", ui_tmp);

    return i_ret == FR_SUCC ? APM_L7_ANALYZE_SUCC : APM_L7_ANALYZE_FAIL;

}


int ldap_protocol_parse_resp(Frbyte_Packet *p_packet, Frreport_body_data *p_st_body_data, unsigned int ui_tmp, L7session_ldap_private *p_st_private)
{
    int i_ret = 0;

    if(p_packet == NULL || p_st_body_data == NULL)
        return FR_FAIL;

    switch (ui_tmp)
    {
        case BIND_RESP:
            i_ret = ldap_get_response(p_packet, p_st_body_data, p_st_private);
            break;

        case SEARCH_RES_DONE:
        case MOD_DN_RESP:
        case ADD_RESP:
        case DEL_RESP:
        case MOD_RESP:
            i_ret = ldap_get_response(p_packet, p_st_body_data, p_st_private);
            if(i_ret == FR_FAIL)
                return FR_FAIL;

            i_ret = frreport_body_l7_add_int(p_st_body_data, "response.ldap.rows", p_st_private->i_ret_rows);
            break;

        case  SERRCH_RES_ENTRY:
            i_ret = ldap_search_res_entry(p_packet, p_st_body_data, p_st_private);
            if(i_ret == FR_SUCC)
            {
                return APM_L7_ANALYZE_TODO;
            }

            break;

        default:
            return APM_L7_ANALYZE_FAIL;
    }

//    if(i_ret == FR_FAIL)
//        printf("ui_tmp = %x\n", ui_tmp);

    return i_ret == FR_SUCC ? APM_L7_ANALYZE_SUCC : APM_L7_ANALYZE_FAIL;

}

//todo
int ldap_parse_req(Frbyte_Packet *p_packet,  Frreport_body_data *p_st_body_data, L7session_ldap_private *p_st_private)
{
    char c_tmp;
    unsigned int ui_data_len = 0;
    int i_ret = 0;

    if(p_packet == NULL || p_st_body_data == NULL || p_st_private == NULL)
        return APM_L7_ANALYZE_FAIL;

    i_ret = bytebuff_get_char(p_packet, (uint8_t *)&c_tmp);
    if(i_ret == APM_L7_ANALYZE_FAIL || c_tmp != '\x30')
        return APM_L7_ANALYZE_FAIL;
    
    i_ret = ldap_get_lenth(p_packet, &ui_data_len);
    if(i_ret == APM_L7_ANALYZE_FAIL)
        return APM_L7_ANALYZE_FAIL;

    if(p_packet->ui_remaining < ui_data_len)
    {
        bytebuff_rewind(p_packet);
        return APM_L7_ANALYZE_TODO;
    }

    i_ret = ldap_get_message_id(p_packet, p_st_body_data, &p_st_private->i_mess_id, FR_YES);
    if(i_ret == FR_FAIL)
        return APM_L7_ANALYZE_FAIL;

    i_ret = ldap_get_protocol(p_packet, p_st_body_data, &p_st_private->i_option);
    if(i_ret == FR_FAIL)
        return APM_L7_ANALYZE_FAIL;

    i_ret = ldap_protocol_parse_req(p_packet, p_st_body_data, (unsigned int)p_st_private->i_option, p_st_private);

    return i_ret;
    
}

int ldap_parse_resp(Frbyte_Packet *p_packet,  Frreport_body_data *p_st_body_data, L7session_ldap_private *p_st_private)
{
    char c_tmp;
    unsigned int ui_data_len = 0;
    int i_ret = 0;
    int i_mess_id = 0;
    int i_option = 0;

    if(p_packet == NULL || p_st_body_data == NULL || p_st_private == NULL)
        return APM_L7_ANALYZE_FAIL;

    i_ret = bytebuff_get_char(p_packet, (uint8_t *)&c_tmp);
    if(i_ret == APM_L7_ANALYZE_FAIL || c_tmp != '\x30')
        return APM_L7_ANALYZE_FAIL;

    i_ret = ldap_get_lenth(p_packet, &ui_data_len);
    if(i_ret == APM_L7_ANALYZE_FAIL)
        return APM_L7_ANALYZE_FAIL;

    if(p_packet->ui_remaining < ui_data_len)
    {
        bytebuff_rewind(p_packet);
        return APM_L7_ANALYZE_TODO;
    }

    i_ret = ldap_get_message_id(p_packet, p_st_body_data, &i_mess_id, FR_NO);
    if(i_ret == FR_FAIL || p_st_private->i_mess_id != i_mess_id)
        return APM_L7_ANALYZE_FAIL;

    i_ret = ldap_get_protocol(p_packet, p_st_body_data, &i_option);
    if(i_ret == FR_FAIL)
        return APM_L7_ANALYZE_FAIL;

    i_ret = ldap_protocol_parse_resp(p_packet, p_st_body_data, (unsigned int)i_option, p_st_private);

    return i_ret;

}

int ldap_direction_detect(char *p_data_in,  int i_data_len)
{
    int i_skip_len = 0;
    int i_op = 0;

    if(p_data_in == NULL || i_data_len < 5)
        return -1;

    //跳过30
    p_data_in++;
    i_data_len --;

    if(*p_data_in > 0x80)
        i_skip_len = (int)(*p_data_in) - 0x80 + 1;
    else
        i_skip_len = 1;

    //跳过长度位
    p_data_in += i_skip_len;
    i_data_len -= i_skip_len;

    if(i_data_len <= 0)
        return -1;

    //跳过messageID
    i_skip_len = (int)(*(p_data_in + 1)) + 2;

    p_data_in += i_skip_len;
    i_data_len -= i_skip_len;

    if(i_data_len <= 0)
        return -1;

    //获取protocolOp
    i_op = (int)(*p_data_in);

    switch(i_op)
    {
        //req
        case BIND_REQ:
        case UNBIND_REQ:
        case SEARCH_REQ:
        case MOD_REQ:
        case ADD_REQ:
        case DEL_REQ:
        case MOD_DN_REQ:
        case COM_REQ:
        case ABAND_REQ:
        case EXT_REQ:
            return 0;

        //resp
        case BIND_RESP:
        case SERRCH_RES_ENTRY:
        case SEARCH_RES_DONE:
        case SEARCH_RES_REF:
        case MOD_RESP:
        case ADD_RESP:
        case DEL_RESP:
        case MOD_DN_RESP:
        case COM_RESP:
        case EXT_RESP:
        case INT_RESP:
            return 1;

        default:
            return -1;

    }

}
